#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    this->ui->setupUi(this);
    this->initComponents();
    this->jarvis = new Jarvis;
    QObject::connect(ui->generateButton, SIGNAL(clicked()), this, SLOT(refreshView()));
    QObject::connect(ui->startButton, SIGNAL(clicked()), this, SLOT(startAlghoritm()));
	QObject::connect(ui->cleanButton, SIGNAL(clicked()), this, SLOT(cleanLines()));
	QObject::connect(ui->actionWczytaj, SIGNAL(activated()), this, SLOT(readFile()));
	QObject::connect(ui->actionZapisz, SIGNAL(activated()), this, SLOT(saveFile()));
}

void MainWindow::initComponents()
{
    // metody do wybrania
    this->ui->comboBox->addItem("standard");
    this->ui->comboBox->addItem("OpenMP");
}

MainWindow::~MainWindow()
{
    delete this->ui;
    delete this->jarvis;
}

void MainWindow::setModel(class Model* _model)
{
    this->model = _model;
}

void MainWindow::refreshView()
{
	logMessage(QString::fromUtf8("generowanie punktów"));
    this->model->setPointsCount(this->ui->spinBox->value());
    this->model->generatePoints();
    this->drawPoints(this->model->getPoints(), this->model->getPointsCount());
	logMessage(QString::fromUtf8("wygenerowano punkty"));
}

void MainWindow::startAlghoritm()
{
    //TODO wybranie wersji  i liczenie czasu
//    this->ui->comboBox
//    this->ui->statusBar
	if (this->model->getPointsCount() == 0 || this->model->getPoints() == NULL)
	{
		showMessage(QString::fromUtf8("Aby rozpocząć należy wygenerować punkty."), QMessageBox::Icon::Warning);
		return;
	}
    int index = this->ui->comboBox->currentIndex();
    switch (index)
    {
        case 0:
            this->startNormal();
			break;
        case 1:
            this->startOpenMP();
			break;
    }
}
void MainWindow::startNormal()
{
	QTime time;
	logMessage(QString::fromUtf8("start standard"));
	if (this->jarvis)
		delete this->jarvis;
	this->jarvis = new Jarvis;
    this->jarvis->setPoints(this->model->getPoints(), this->model->getPointsCount());
	time.start();
    this->jarvis->process();
	int dif = time.elapsed();
    this->drawLines(this->jarvis->getEdgesPoints(), this->jarvis->getEdgesPoitnsCount());
	logMessage(QString::fromUtf8("koniec standard: %1 ms").arg(dif));
}

void MainWindow::startOpenMP()
{
	int nThreads = 0;
	QTime time;
	logMessage(QString::fromUtf8("start openMP"));
	if (this->jarvis)
		delete this->jarvis;
	this->jarvis = new Jarvis_omp;
	this->jarvis->setPoints(this->model->getPoints(), this->model->getPointsCount());
	time.start();
	nThreads = this->jarvis->process();
	int dif = time.elapsed();
	this->drawLines(this->jarvis->getEdgesPoints(), this->jarvis->getEdgesPoitnsCount());
	logMessage(QString::fromUtf8("koniec openMP: %1 ms").arg(dif));
	logMessage(QString::fromUtf8("liczba wątków: %1").arg(nThreads));
}

/**
 * @brief MainWindow::drawPoints rysowanie punktów na panelu
 * @param points tablica punktów [x, y]
 * @param pointsCount liczba punktów
 */
void MainWindow::drawPoints(struct Point *points, int pointsCount)
{
    QGraphicsScene* scene = this->ui->graphicsView->scene();
    if (!scene)
    {
        scene = new QGraphicsScene;
        this->ui->graphicsView->setScene(scene);
    }
    scene->clear();
    for (int i=0; i<pointsCount; ++i)
    {
        int x = points[i].x;
        int y = points[i].y;
        scene->addLine(x, y, x+1, y, QPen(QBrush(Qt::blue),2));
    }
    this->ui->graphicsView->setScene(scene);
    this->ui->graphicsView->repaint();
}

/**
 * @brief MainWindow::drawLines rysowanie linii otoczki
 * @param points punkty otoczki
 * @param pointCount liczba punktów otoczki
 */
void MainWindow::drawLines(struct Point* points, int pointCount)
{
    QGraphicsScene* scene = this->ui->graphicsView->scene();
    for (int i=0; i<pointCount-1; ++i)
        scene->addLine(points[i].x, points[i].y, points[i+1].x, points[i+1].y, QPen(QBrush(Qt::red), 2));
    this->ui->graphicsView->setScene(scene);
    this->ui->graphicsView->repaint();
}

void MainWindow::cleanLines()
{
	this->drawPoints(this->model->getPoints(), this->model->getPointsCount());
}

void MainWindow::showMessage(QString message, QMessageBox::Icon icon)
{
	 QMessageBox msgBox;
	 msgBox.setText(message);
	 msgBox.setIcon(icon);
	 msgBox.exec();
}

void MainWindow::logMessage(QString message)
{
	QString text = this->ui->textEdit->toPlainText();
	text.append(message);
	text.append(QString("\n"));
	this->ui->textEdit->setText(text);
	this->ui->textEdit->moveCursor(QTextCursor::MoveOperation::End, QTextCursor::MoveMode::MoveAnchor);
		
}

// wczytanie z pliku puktów i krawędzi
void MainWindow::readFile() 
{
	QString fileName = QFileDialog::getOpenFileName(this, QString::fromUtf8("Otwórz"), "", tr("Files (*.porr)"));
	std::fstream file(fileName.toStdString(), std::ios::in);
	std::string line;
	if (file.is_open())
	{
		std::getline(file, line);
		if (line != POINTS)
		{
			return;
		}
		std::getline(file, line);
		std::istringstream iss(line);
		int pCount;
		iss >> pCount;
		this->model->setPointsCount(pCount);
		Point* points = new Point[pCount];
		
		for (int i=0; i<pCount; ++i)
		{
			std::getline(file, line);
			Point p;
			std::string str = line.substr(1, line.find(POINTS_SEPARATOR));
			iss = std::istringstream(str);
			iss >> p.x;
			str = line.substr(line.find(POINTS_SEPARATOR) + POINTS_SEPARATOR_LEN, line.length() - line.find(POINTS_SEPARATOR) - POINTS_SEPARATOR_LEN);
			iss = std::istringstream(str);
			iss >> p.y;
			points[i] = p;
		}
		this->model->setPoints(points);
		this->jarvis->setPoints(points, pCount);
		this->drawPoints(this->model->getPoints(), this->model->getPointsCount());
		
		// czytanie punktów krawędzi
		std::getline(file, line);
		std::getline(file, line);
		if (line != EDGE_POINTS)
		{
			return;
		}
		std::getline(file, line);
		iss = std::istringstream(line);
		pCount;
		iss >> pCount;
		points = new Point[pCount];
		
		for (int i=0; i<pCount; ++i)
		{
			std::getline(file, line);
			Point p;
			float tmp;
			std::string str = line.substr(1, line.find(POINTS_SEPARATOR));
			iss = std::istringstream(str);
			iss >> tmp;
			p.x = tmp;
			str = line.substr(line.find(POINTS_SEPARATOR) + POINTS_SEPARATOR_LEN, line.length() - line.find(POINTS_SEPARATOR) - POINTS_SEPARATOR_LEN);
			iss = std::istringstream(str);
			iss >> tmp;
			p.y = tmp;
			points[i] = p;
		}
		this->jarvis->loadEdgesPoints(pCount, points);
		this->drawLines(this->jarvis->getEdgesPoints(), this->jarvis->getEdgesPoitnsCount());
	}

}

// zapisanie punktów i krawędzi
void MainWindow::saveFile()
{
	if (this->model->getPointsCount() > 0)
	{
		QString fileName = QFileDialog::getSaveFileName(this, QString::fromUtf8("Zapisz"), "", tr("Files (*.porr)"));
		std::fstream file(fileName.toStdString(), std::ios::out);
		file << POINTS << std::endl;
		file << this->model->getPointsCount() << std::endl;
		Point* points = model->getPoints();
		for (int i=0; i<model->getPointsCount(); ++i) 
		{
			file << OPEN_BRACKET << points[i].x << POINTS_SEPARATOR << points[i].y << CLOSE_BRACKET  << std::endl; 
		}
		if (this->jarvis->getEdgesPoitnsCount() > 0)
		{
			points = jarvis->getEdgesPoints();
			file << std::endl << EDGE_POINTS << std::endl;
			file << this->jarvis->getEdgesPoitnsCount() << std::endl;
			for (int i=0; i<jarvis->getEdgesPoitnsCount(); ++i) 
			{
				file << OPEN_BRACKET << points[i].x << POINTS_SEPARATOR << points[i].y << CLOSE_BRACKET << std::endl; 
			}
			file.close();
		}
	}
}

